Могут существовать два вида операций
Обычные вычисления и IO операции
IO операции требуют много времени на ожидание
Статусы Тредов:
Native thread - это потоки, созданные и управляемые непосредственно операционной системой.
Существует thread API
Thread th = new Thread(...);
// вот здесь появляется native thread
th.Start(arg);
// Контекст свитчнется к другому треду, но этот тред продолжит выполнение на том же CPU.
// Оптимизация в том, что все будет в кэше
Thread.Yeild();
// Вызовет микропаузу на процессоре.
// Если есть како-то тред в рэйди статусе, то контекст переключится
// Если другого такого треда нет, то переключение не произойдет
Thread.Sleep(0)
SpinWait
в .NET — это структура, предоставляющая механизм для активного ожидания (busy-waiting) в многопоточном программировании. Вместо того чтобы блокировать поток и вызывать переключение контекста, как это делает Thread.Sleep
или синхронизационные примитивы, такие как мьютексы или семафоры, SpinWait
удерживает поток активным, выполняя циклы ожидания. Это полезно в сценариях, где ожидаемое время ожидания короткое, и переключение контекста может быть более затратным, чем активное ожидание.
CPU-bound задачи ограничены в своей производительности мощностью процессора. Это означает, что для выполнения таких задач требуется интенсивная работа процессора, и они выполняются быстрее, если использовать более быстрый или более мощный процессор. Примеры CPU-bound задач включают сложные вычисления, такие как численные методы, рендеринг графики, шифрование и декодирование данных.
I/O-bound задачи ограничены скоростью ввода-вывода (I/O), то есть они зависят от скорости доступа к диску, сети или другим периферийным устройствам. Такие задачи часто ожидают завершения операций ввода-вывода, и их производительность не увеличится значимо с более мощным процессором. Примеры I/O-bound задач включают чтение и запись файлов, сетевое взаимодействие и доступ к базам данных.
типы тредов:
IOCP работают поверх:
Виды очередей:
Алгоритм работы треда:
Во время замкания, для захвата переменной, компилятор, в месте где первоначально объявляется переменная создает объект класса, в котором будет один метод, тот самый делегат и поле которое будет захватывать перменную. Далее, вместо работы с самой переменной будет происходить работа с полем внутри этого объекта содержащего делегат.
как из создавать
Многопоточность - это когда "много потоков" - почти что отдельных процессов, но использующих общую память с основным, а асинхронность - когда поток-процесс всего один, но он выполняет разные задачи по очереди с переключениями в моменты ожиданий задачами ввода-вывода или результатов выполнения другой задачи/функции.
использование этих штук просто перерабатывает метод в стэйт машину.
Создается класс в режиме дебага или структура в режиме релиза, которая реализует интерфейс IAsyncStateMachine
Создается объект AsyncTaskMethodBuilder
В нем вызывается метод Start и передается наша стэйт машина
В классе стэйт машины будет один метод MoveNext() который будет исполнять наш код по состояниям. Состояния разделяются с помощью await. В стэйт машине на месте эвэйт будет происходить проверка закончилась ли таска, которую мы ждем с помощью await. Если не закончилась, то стейт машина запоминает на каком она состоянии и передает в AsyncTaskMethodBuilder ссылку на себя и на таску которую надо асинхронно ждать.
Далее, когда таска выполняется, билдер снова запускает стейт машину до следующего состояния. Так продолжается пока MoveNext полноценно не завершится
По терминологии: рассматриваемый асинхронный метод, чей код будет рассматриваться, я буду называть асинхронный метод, а вызываемые асинхронные методы внутри него я буду называть асинхронная операция.
Блокировка потока означает, что поток из пула потоков будет ожидать когда завершиться метод и этот поток не сможет работать в других метах. Стэйт машина позволяет сохранить состояние и отпустить поток. Join - блокирует поток.
Исключения ловятся в билдере и для этого используется возврат Task
В данном коде, метод Do завершится не ожидая DoAsync так как нет await или GetAwaiter().GetResult()
То есть, стейтмашина создается, запускается, но её выполнения никто не ждет
ConfigurationAwait можно вызывать у объекта таски и передавать фолс, это будет означать для ОС, что контекст подтаскивать не обязательно, в ASP это уже по умолчанию включено
Чтобы работало await достаточно реализовать у класса метод GetAwaiter(), таким образом можно эвэитить даже инт.